#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
自动排班调度器

实现基于任务完成后计时的自动排班机制，确保每次排班任务之间有足够的间隔，
避免任务堆积和跳过，提高系统的可靠性和稳定性。

作者: AI助手
日期: 2023-05-20
"""

import logging
import threading
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, Callable

# 配置日志
logger = logging.getLogger(__name__)


class AutoScheduler:
    """自动排班调度器
    
    实现基于任务完成后计时的自动排班机制，确保每次排班任务之间有足够的间隔。
    """
    
    def __init__(self):
        """初始化自动排班调度器"""
        self.timer: Optional[threading.Timer] = None
        self.is_running: bool = False
        self.app_context = None
        self.schedule_func: Optional[Callable] = None
        self.interval_minutes: int = 7
        self.enabled: bool = False
        self.last_run_time: Optional[datetime] = None
        self.next_run_time: Optional[datetime] = None
    
    def initialize(self, app, schedule_func: Callable, interval_minutes: int = 7, enabled: bool = False):
        """初始化自动排班调度器
        
        Args:
            app: Flask应用实例
            schedule_func: 排班函数
            interval_minutes: 排班间隔（分钟）
            enabled: 是否启用自动排班
        """
        self.app_context = app.app_context
        self.schedule_func = schedule_func
        self.interval_minutes = interval_minutes
        self.enabled = enabled
        
        logger.info(f"自动排班调度器初始化完成，间隔 {interval_minutes} 分钟，{'启用' if enabled else '禁用'}")
    
    def start(self, run_immediately: bool = True):
        """启动自动排班调度器
        
        Args:
            run_immediately: 是否立即执行一次排班
        """
        if not self.enabled:
            logger.info("自动排班功能未启用，不启动调度器")
            return
        
        if not self.schedule_func:
            logger.error("排班函数未设置，无法启动调度器")
            return
        
        self.is_running = True
        
        if run_immediately:
            logger.info("立即执行一次自动排班...")
            self._run_schedule_task()
        else:
            self._schedule_next_run()
        
        logger.info(f"自动排班调度器已启动，间隔 {self.interval_minutes} 分钟")
    
    def stop(self):
        """停止自动排班调度器"""
        self.is_running = False
        
        if self.timer:
            self.timer.cancel()
            self.timer = None
        
        logger.info("自动排班调度器已停止")
    
    def _run_schedule_task(self):
        """执行排班任务"""
        if not self.is_running:
            return
        
        self.last_run_time = datetime.now()
        
        try:
            with self.app_context():
                logger.info(f"开始执行自动排班任务，时间: {self.last_run_time}")
                result = self.schedule_func()
                logger.info(f"自动排班任务执行完成，结果: {result}")
        except Exception as e:
            logger.error(f"自动排班任务执行出错: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
        
        # 安排下一次排班
        self._schedule_next_run()
    
    def _schedule_next_run(self):
        """安排下一次排班"""
        if not self.is_running:
            return
        
        # 取消现有的定时器
        if self.timer:
            self.timer.cancel()
        
        # 计算下一次排班时间
        self.next_run_time = datetime.now() + timedelta(minutes=self.interval_minutes)
        
        # 创建新的定时器
        self.timer = threading.Timer(self.interval_minutes * 60, self._run_schedule_task)
        self.timer.daemon = True  # 设置为守护线程，确保应用退出时线程也会退出
        self.timer.start()
        
        logger.info(f"下一次自动排班将在 {self.next_run_time} 执行，间隔 {self.interval_minutes} 分钟")
    
    def update_interval(self, interval_minutes: int):
        """更新排班间隔
        
        Args:
            interval_minutes: 排班间隔（分钟）
        """
        if interval_minutes <= 0:
            logger.error(f"排班间隔必须大于0，当前值: {interval_minutes}")
            return
        
        self.interval_minutes = interval_minutes
        
        if self.is_running:
            logger.info(f"排班间隔已更新为 {interval_minutes} 分钟，将在下一次排班后生效")
    
    def get_status(self) -> Dict[str, Any]:
        """获取调度器状态
        
        Returns:
            调度器状态信息
        """
        return {
            "enabled": self.enabled,
            "is_running": self.is_running,
            "interval_minutes": self.interval_minutes,
            "last_run_time": self.last_run_time.isoformat() if self.last_run_time else None,
            "next_run_time": self.next_run_time.isoformat() if self.next_run_time else None,
        }


# 创建全局自动排班调度器实例
auto_scheduler = AutoScheduler()
